﻿using Module.FlowChart.Model;
using Module.FlowChart.View;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace Module.FlowChart.RunAble.View
{
    internal abstract class PageDrawer_FlowChart : PageDrawer
    {
        public int LinkAbleCycleR = 10;
        public int GridWidth = 30;

        public ViewManager_Info Info;



        #region GDI 绘制
        Pen NodePen;
        Pen LinePen;
        SolidBrush NodeBackBrush;
        SolidBrush StrBrush;
        Font font;
        StringFormat StringCenter;
        Pen GridPen = new Pen(Color.Gray, 0.3f);
        #endregion


        public PageDrawer_FlowChart(ViewManager_Info info) : base()
        {
            Info = info;
            //************************* 初始化绘制工具
            NodePen = new Pen(Color.Blue, 2);
            LinePen = new Pen(Color.Blue, 2);
            StrBrush = new SolidBrush(Color.Black);
            NodeBackBrush = new SolidBrush(Color.Yellow);
            font = new Font("宋体", 1 /*20 * Scale*/);
            StringCenter = new StringFormat()
            {
                LineAlignment = StringAlignment.Center,
                Alignment = StringAlignment.Center
            };
        }


        public sealed override void Refresh(Graphics g = null)
        {
            if (Info.Container.Size.Width <= 0 || Info.Container.Size.Height <= 0)
            {
                return;
            }
            Info.Drawed();

            Bitmap b = new Bitmap(Info.Container.Size.Width, Info.Container.Size.Height);
            Graphics bg = Graphics.FromImage(b);
            bg.SmoothingMode = SmoothingMode.AntiAlias;
            bg.Clear(Color.White);
            //刷新背景层
            DrawBackGround(bg);
            //绘制节点和线
            DrawNodesAndLines(bg);
            //刷新活跃的节点
            DrawFront(bg);
            //Info.Container.BackgroundImage = b;
            if (g == null)
                g = Info.Container.CreateGraphics();
            g.DrawImage(b, 0, 0);
            b.Dispose();
            g.Dispose();
        }
        protected void DrawBackGround(Graphics g)
        {
            float grid_line_width = 1;
            float Scale = Info.Scale;
            Point LeftTop = Info.LeftTop;
            //绘制网格
            Pen pen = GridPen;
            pen.Width = grid_line_width * Scale;
            for (int i = (int)((GridWidth - LeftTop.X % GridWidth) * Scale); i < Info.Container.Width; i += (int)(GridWidth * Scale))
            {
                g.DrawLine(pen, i, 0, i, Info.Container.Height);
            }
            for (int i = (int)((GridWidth - LeftTop.Y % GridWidth) * Scale); i < Info.Container.Height; i += (int)(GridWidth * Scale))
            {
                g.DrawLine(pen, 0, i, Info.Container.Width, i);
            }
        }
        protected virtual void DrawNodesAndLines(Graphics g)
        {
            float Scale = Info.Scale;
            Point LeftTop = Info.LeftTop;
            //绘制其他元素
            NodePen.Color = Color.Gray;
            NodePen.Width = Scale * 4;
            LinePen.Color = Color.Blue;
            LinePen.Width = Scale * 2;

            // 绘制没有激活的线
            foreach (var line in Info.Page.Lines.Values)
            {
                DrawDisActiveLine(g, line);
            }

            //绘制没有激活的节点
            foreach (var node in Info.Page.Nodes.Values)
            {

                DrawDisActiveNode(g, node);
            }
        }
        /// <summary>
        /// 绘制未激活的单个节点
        /// </summary>
        /// <param name="node"></param>
        protected virtual void DrawDisActiveNode(Graphics g, FCNode node)
        {
            if (!node.Visible || !node.IsInWindow)
                return;
            float nodelinewidth = 2;
            NodePen.Width = nodelinewidth * Info.Scale;
            Font font = new Font(node.Font.FontFamily, node.Font.Size * Info.Scale, node.Font.Style);
            NodeBackBrush.Color = node.BackGroundColor;
            Rectangle rect = node.RealRect;
            switch (node.Shape)
            {
                case Shape.Non:
                    throw new System.Exception("未知图形");
                case Shape.Rect:
                    g.FillRectangle(NodeBackBrush, rect);
                    g.DrawRectangle(NodePen, rect);
                    break;
                case Shape.Circular:
                    //绘制实心
                    g.FillEllipse(NodeBackBrush, rect);
                    //绘制边框
                    g.DrawEllipse(NodePen, rect);
                    break;
                case Shape.Diamond:
                    g.FillDiamond(NodeBackBrush, rect);
                    g.DrawDiamond(NodePen, rect);
                    break;
                case Shape.Parallelogram:
                    g.FillParallelogram(NodeBackBrush, rect, 0.2f, 0);
                    g.DrawParallelogram(NodePen, rect, 0.2f, 0);
                    break;
                default:
                    break;
            }

            switch (node.Type)
            {
                case FCNodeType.Terminal:
                    //绘制文本
                    g.DrawString(node.GetNodeText(), font, StrBrush, rect, StringCenter);
                    break;
                case FCNodeType.Assign:
                    g.DrawString(node.GetNodeText(), font, StrBrush, rect, StringCenter);
                    break;
                case FCNodeType.IF:
                    g.DrawString(node.GetNodeText(), font, StrBrush, rect, StringCenter);
                    SizeF s = g.MeasureString("是", font);
                    g.DrawString("是", font, StrBrush, new RectangleF(rect.X - s.Width, rect.Y + rect.Height / 2 - s.Height / 2, s.Width, s.Height), StringCenter);
                    g.DrawString("否", font, StrBrush, new RectangleF(rect.X + rect.Width, rect.Y + rect.Height / 2 - s.Height / 2, s.Width, s.Height), StringCenter);
                    //g.DrawString("是", font, StrBrush, new RectangleF(rect.X-s.Width/2,rect.Y+rect.Height/2-s.Height / 2, s.Width,s.Height), StringCenter);
                    //g.DrawString("否", font, StrBrush, new RectangleF(rect.X+rect.Width - s.Width/2, rect.Y+ rect.Height / 2 - s.Height / 2, s.Width, s.Height), StringCenter);
                    break;
                case FCNodeType.IO:
                    g.DrawString(node.GetNodeText(), font, StrBrush, rect, StringCenter);
                    break;
                case FCNodeType.Label:
                    g.DrawString(node.GetNodeText(), font, StrBrush, rect, StringCenter);
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// 绘制未激活单个连线
        /// </summary>
        protected virtual void DrawDisActiveLine(Graphics g, FCLine line)
        {
            if (!line.Visible || !line.IsInWindow)
                return;
            for (int i = 1; i < line.RealPoints.Length - 1; i++)
            {
                LinePen.EndCap = LineCap.NoAnchor;
                g.DrawLine(LinePen, line.RealPoints[i - 1], line.RealPoints[i]);
            }
            if (line.RealPoints.Length >= 2)
            {
                LinePen.CustomEndCap = new AdjustableArrowCap(6, 6, true);
                g.DrawLine(LinePen, line.RealPoints[line.RealPoints.Length - 2], line.RealPoints[line.RealPoints.Length - 1]);
            }
        }

        protected void DrawFront(Graphics g)
        {
            float Scale = Info.Scale;

            NodePen.Color = Color.Gray;
            NodePen.Width = Scale * 4;
            LinePen.Width = Scale * 2;

            if (Info.SelectedNode > 0)
            {
                var node = Info.Page.FindNode(Info.SelectedNode);
                Rectangle rect = node.RealRect;
                NodePen.Width = 4 * Info.Scale;
                NodePen.Color = Color.Red;
                switch (node.Shape)
                {
                    case Shape.Non:
                        throw new System.Exception("未知图形");
                    case Shape.Rect:
                        g.DrawRectangle(NodePen, rect);
                        break;
                    case Shape.Circular:
                        g.DrawEllipse(NodePen, rect);
                        break;
                    case Shape.Diamond:
                        g.DrawDiamond(NodePen, rect);
                        break;
                    case Shape.Parallelogram:
                        g.DrawParallelogram(NodePen, rect, 0.2f, 0);
                        break;
                    default:
                        break;
                }
            }

            if (Info.CurrentPointTo > 0)
            {
                var node = Info.Page.FindNode(Info.CurrentPointTo);
                DrawNodeLinkAblePosition(g, node);
                DrawNodeResizeAblePosition(g, node);
            }

            if (Info.IsRunning() && Info.HighLightNode > 0)
            {
                int arrlength = 100; int arrheight = 50;
                var node = Info.Page.FindNode(Info.HighLightNode);
                Rectangle rect = new Rectangle(node.RealRect.X - arrlength, node.RealRect.Y + node.RealRect.Height / 2 - arrheight / 2,
                    arrlength, arrheight);
                g.FillArrow(new SolidBrush(Color.Red), rect, 0.5f, 0.2f);
            }


            //if (ActiveNode.Count > 0)
            //{
            //    foreach (var nodeid in ActiveNode)
            //    {
            //        var node = doc.FindNode(nodeid);
            //        DrawNodeLinkAblePosition(g, node);
            //    }
            //    //todo 绘制激活的节点
            //}

            //if (IsLinking)
            //{
            //    FCNode l = doc.FindNode(LinkStartNode);
            //    Point[] points = LineManager.GetLinePoints(new Rectangle(l.Position, l.Size), LinkAnchor, MousePoint);
            //    points[0] = DocPosToContainerPos(points[0]);
            //    for (int i = 1; i < points.Length; i++)
            //    {
            //        points[i] = DocPosToContainerPos(points[i]);
            //        g.DrawLine(NodePen, points[i - 1], points[i]);
            //    }
            //}


        }


        public virtual void DrawNodeLinkAblePosition(Graphics g, FCNode node)
        {
            float Scale = Info.Scale;
            int w = (int)(LinkAbleCycleR / 2 * Scale);
            int w2 = (int)(LinkAbleCycleR * Scale);
            Rectangle rect = node.RealRect;
            if (Info.IsLinkingNode)
            {//linkto
                switch (node.Type)
                {
                    case FCNodeType.Terminal:
                        if (!node.IsStartNode)
                            g.DrawEllipse(LinePen, rect.X + rect.Width / 2 - w, rect.Y - w, w2, w2);
                        break;
                    case FCNodeType.Assign:
                    case FCNodeType.Label:
                        g.DrawEllipse(LinePen, rect.X + rect.Width / 2 - w, rect.Y - w, w2, w2);
                        g.DrawEllipse(LinePen, rect.X + rect.Width - w, rect.Y + rect.Height / 2 - w, w2, w2);
                        g.DrawEllipse(LinePen, rect.X + rect.Width / 2 - w, rect.Y + rect.Height - w, w2, w2);
                        g.DrawEllipse(LinePen, rect.X - w, rect.Y + rect.Height / 2 - w, w2, w2);
                        break;
                    case FCNodeType.IF:
                        g.DrawEllipse(LinePen, rect.X + rect.Width / 2 - w, rect.Y - w, w2, w2);
                        break;
                    case FCNodeType.IO:
                        g.DrawEllipse(LinePen, rect.X + rect.Width / 2 - w, rect.Y - w, w2, w2);
                        break;
                    default:
                        break;
                }
            }
            else
            {//linkfrom
                switch (node.Type)
                {
                    case FCNodeType.Terminal:
                        if (node.IsStartNode)
                            g.DrawEllipse(LinePen, rect.X + rect.Width / 2 - w, rect.Y + rect.Height - w, w2, w2);
                        break;
                    case FCNodeType.Assign:
                    case FCNodeType.Label:
                        g.DrawEllipse(LinePen, rect.X + rect.Width / 2 - w, rect.Y - w, w2, w2);
                        g.DrawEllipse(LinePen, rect.X + rect.Width - w, rect.Y + rect.Height / 2 - w, w2, w2);
                        g.DrawEllipse(LinePen, rect.X + rect.Width / 2 - w, rect.Y + rect.Height - w, w2, w2);
                        g.DrawEllipse(LinePen, rect.X - w, rect.Y + rect.Height / 2 - w, w2, w2);
                        break;
                    case FCNodeType.IF:
                        g.DrawEllipse(LinePen, rect.X + rect.Width - w, rect.Y + rect.Height / 2 - w, w2, w2);
                        g.DrawEllipse(LinePen, rect.X - w, rect.Y + rect.Height / 2 - w, w2, w2);
                        break;
                    case FCNodeType.IO:
                        g.DrawEllipse(LinePen, rect.X + rect.Width / 2 - w, rect.Y + rect.Height - w, w2, w2);
                        break;
                    default:
                        break;
                }
            }

        }

        public virtual void DrawNodeResizeAblePosition(Graphics g, FCNode node)
        {
            float Scale = Info.Scale;
            int w = (int)(LinkAbleCycleR / 2 * Scale);
            int w2 = (int)(LinkAbleCycleR * Scale);
            Rectangle rect = node.RealRect;
            g.DrawRectangle(LinePen, rect.X - w, rect.Y - w, w2, w2);
            g.DrawRectangle(LinePen, rect.X + rect.Width - w, rect.Y - w, w2, w2);
            g.DrawRectangle(LinePen, rect.X + rect.Width - w, rect.Y + rect.Height - w, w2, w2);
            g.DrawRectangle(LinePen, rect.X - w, rect.Y + rect.Height - w, w2, w2);
        }


    }
}